using System;
using System.Text;

namespace RBAC.Read.Api.Utils
{
    /// <summary>
    /// HTTP响应头帮助类，用于安全地设置响应头
    /// </summary>
    public static class HttpHeaderHelper
    {
        /// <summary>
        /// 验证HTTP头值是否安全
        /// </summary>
        /// <param name="headerValue">要验证的头值</param>
        /// <returns>是否安全</returns>
        public static bool IsSafeHeaderValue(string headerValue)
        {
            if (string.IsNullOrEmpty(headerValue))
                return false;

            foreach (char c in headerValue)
            {
                // 检查是否为控制字符或非ASCII字符
                if (c < 32 || c > 126)
                    return false;
            }
            return true;
        }

        /// <summary>
        /// 清理HTTP头值中的不安全字符
        /// </summary>
        /// <param name="headerValue">原始头值</param>
        /// <returns>清理后的头值</returns>
        public static string SanitizeHeaderValue(string headerValue)
        {
            if (string.IsNullOrEmpty(headerValue))
                return string.Empty;

            var sb = new StringBuilder();
            foreach (char c in headerValue)
            {
                if (c >= 32 && c <= 126) // 可打印的ASCII字符
                {
                    sb.Append(c);
                }
                else
                {
                    sb.Append('_');
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// 生成安全的Content-Disposition头值
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="isAttachment">是否为附件</param>
        /// <returns>安全的Content-Disposition头值</returns>
        public static string GenerateSafeContentDisposition(string fileName, bool isAttachment = true)
        {
            if (string.IsNullOrEmpty(fileName))
                return isAttachment ? "attachment" : "inline";

            var disposition = isAttachment ? "attachment" : "inline";
            
            // 如果文件名包含非ASCII字符，使用RFC 5987标准
            if (!IsSafeHeaderValue(fileName))
            {
                var safeFileName = SanitizeFileName(fileName);
                var encodedFileName = Uri.EscapeDataString(fileName);
                return $"{disposition}; filename=\"{safeFileName}\"; filename*=UTF-8''{encodedFileName}";
            }
            
            return $"{disposition}; filename=\"{fileName}\"";
        }

        /// <summary>
        /// 清理文件名中的不安全字符
        /// </summary>
        /// <param name="fileName">原始文件名</param>
        /// <returns>清理后的文件名</returns>
        public static string SanitizeFileName(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
                return string.Empty;

            var invalidChars = System.IO.Path.GetInvalidFileNameChars();
            var sanitized = fileName;

            foreach (char invalidChar in invalidChars)
            {
                sanitized = sanitized.Replace(invalidChar, '_');
            }

            // 移除或替换非ASCII字符
            var sb = new StringBuilder();
            foreach (char c in sanitized)
            {
                if (c <= 127) // ASCII字符
                {
                    sb.Append(c);
                }
                else
                {
                    sb.Append('_');
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// 生成安全的文件名（用于HTTP头）
        /// </summary>
        /// <param name="prefix">文件名前缀</param>
        /// <param name="extension">文件扩展名</param>
        /// <returns>安全的文件名</returns>
        public static string GenerateSafeFileName(string prefix, string extension)
        {
            var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
            return $"{prefix}_{timestamp}.{extension.TrimStart('.')}";
        }

        /// <summary>
        /// 验证并设置安全的响应头
        /// </summary>
        /// <param name="response">HTTP响应对象</param>
        /// <param name="headerName">头名称</param>
        /// <param name="headerValue">头值</param>
        /// <returns>是否设置成功</returns>
        public static bool TrySetSafeHeader(Microsoft.AspNetCore.Http.HttpResponse response, string headerName, string headerValue)
        {
            try
            {
                if (IsSafeHeaderValue(headerValue))
                {
                    response.Headers[headerName] = headerValue;
                    return true;
                }
                else
                {
                    var safeValue = SanitizeHeaderValue(headerValue);
                    response.Headers[headerName] = safeValue;
                    return false; // 表示值被清理过
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 设置文件下载响应头
        /// </summary>
        /// <param name="response">HTTP响应对象</param>
        /// <param name="fileName">文件名</param>
        /// <param name="fileSize">文件大小</param>
        /// <param name="contentType">内容类型</param>
        public static void SetFileDownloadHeaders(Microsoft.AspNetCore.Http.HttpResponse response, string fileName, long fileSize, string contentType)
        {
            try
            {
                // 设置Content-Disposition
                var contentDisposition = GenerateSafeContentDisposition(fileName, true);
                response.Headers["Content-Disposition"] = contentDisposition;

                // 设置其他必要的头
                response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
                response.Headers["Pragma"] = "no-cache";
                response.Headers["Expires"] = "0";
                response.Headers["Content-Length"] = fileSize.ToString();
                response.Headers["Content-Type"] = contentType;
            }
            catch (Exception ex)
            {
                // 记录错误但不抛出异常
                System.Diagnostics.Debug.WriteLine($"设置文件下载响应头失败: {ex.Message}");
            }
        }
    }
} 